package com.em.sugarfight.service.engine;

import com.em.sugarfight.entity.*;
import com.em.sugarfight.sugarEnums.*;
import com.em.sugarfight.util.CoordinateConverter;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.stereotype.Component;

import java.util.*;

@Component
public class BombStrategyEngine {

    private static final Logger logger = LoggerFactory.getLogger(BombStrategyEngine.class);

    private int placeBombTick = 0;

    /**
     * 炸弹决策主方法
     * @param gameState 当前游戏状态
     * @return 是否应该放置炸弹
     */
    public boolean shouldPlaceBomb(GameState gameState) {
        PlayerStateVo myPlayer = gameState.getMy_player();
        Position currentPos = CoordinateConverter.pixelToGrid(myPlayer.getPosition());

        // 基础条件检查
        if (!canPlaceBomb(myPlayer,gameState.getCurrent_tick())) {
            return false;
        }

        // 安全检查：确保有逃生路线
//        if (!hasEscapeRoute(currentPos, gameState, dangerMap)) {
//            return false;
//        }

        // 战术价值评估
        double bombValue = evaluateBombPlacement(currentPos, gameState);

        // 决策阈值
        if(bombValue >= 10){
            placeBombTick = gameState.getCurrent_tick();
            return true;
        }else
            return false;
    }

    /**
     * 检查是否能放置炸弹
     */
    private boolean canPlaceBomb(PlayerStateVo player,int current_tick) {
        // 有炸弹包且状态正常
        return player.getBomb_pack_count() > 0 && "A".equals(player.getStatus().name()) && current_tick - placeBombTick > 20;
    }

    /**
     * 检查是否有安全的逃生路线
     */
    private boolean hasEscapeRoute(Position bombPos, GameState gameState, DangerMap dangerMap) {
        // 模拟放置炸弹后的危险地图
        DangerMap futureMap = simulateBombPlacement(bombPos, gameState, dangerMap);

        // BFS搜索安全位置
        Queue<Position> queue = new LinkedList<>();
        Set<Position> visited = new HashSet<>();
        int maxSearchDepth = 5; // 限制搜索深度避免性能问题

        queue.offer(bombPos);
        visited.add(bombPos);

        for (int depth = 0; depth < maxSearchDepth && !queue.isEmpty(); depth++) {
            int levelSize = queue.size();

            for (int i = 0; i < levelSize; i++) {
                Position current = queue.poll();

                // 检查四个方向
                for (Direction dir : Arrays.asList(Direction.U, Direction.D, Direction.L, Direction.R)) {
                    Position nextPos = current.move(dir);

                    if (isValidPosition(nextPos, gameState) && !visited.contains(nextPos)) {
                        visited.add(nextPos);

                        // 找到安全位置
                        if (!futureMap.isInDanger(nextPos)) {
                            return true;
                        }

                        queue.offer(nextPos);
                    }
                }
            }
        }

        return false; // 没有找到安全逃生路线
    }

    /**
     * 模拟放置炸弹后的危险地图
     */
    private DangerMap simulateBombPlacement(Position bombPos, GameState gameState, DangerMap currentDangerMap) {
        // 创建新的危险地图副本
        DangerMap simulatedMap = new DangerMap(gameState.getMapWidth(), gameState.getMapHeight());

        // 复制当前所有危险
        copyDangerMap(currentDangerMap, simulatedMap);

        // 添加新炸弹的威胁
        PlayerStateVo myPlayer = gameState.getMy_player();
        int bombRange = calculateBombRange(myPlayer);
        int explodeTime = 20; // 假设炸弹3秒后爆炸

        Bomb simulatedBomb = new Bomb(bombPos, myPlayer.getId(), myPlayer.getTeam(), bombRange, gameState.getCurrent_tick()+explodeTime);
        simulatedMap.markBombDanger(simulatedBomb,gameState.getCurrent_tick());

        return simulatedMap;
    }

    /**
     * 评估炸弹放置的战术价值
     */
    private double evaluateBombPlacement(Position bombPos, GameState gameState) {
        double totalValue = 0;

        // 1. 伤害价值：能炸到的敌人
        totalValue += calculateDamageValue(bombPos, gameState);

        // 2. 阻断价值：阻止敌人移动
//        totalValue += calculateBlockValue(bombPos, gameState);

//        // 3. 区域控制价值：控制关键区域
//        totalValue += calculateControlValue(bombPos, gameState);

        // 4. 破坏价值：摧毁障碍物
        totalValue += calculateDestructionValue(bombPos, gameState);

        return totalValue;
    }

    /**
     * 计算伤害价值 - 能炸到多少敌人
     */
    private double calculateDamageValue(Position bombPos, GameState gameState) {
        double damageValue = 0;
        PlayerStateVo myPlayer = gameState.getMy_player();
        int bombRange = calculateBombRange(myPlayer);

        // 检查爆炸范围内的敌人
        List<Position> explosionArea = getExplosionArea(bombPos, bombRange, gameState);

        for (PlayerStateVo enemy : getEnemies(gameState)) {
            Position enemyPos = CoordinateConverter.pixelToGrid(enemy.getPosition());

            if (explosionArea.contains(enemyPos)) {
                double enemyValue = 5; // 基础击杀价值

                // 已经晕眩的敌人价值更高
                if ("D".equals(enemy.getStatus().name())) {
                    enemyValue += 10;
                }

                // 敌人道具越多价值越高
                int enemyItems = enemy.getBomb_pack_count() + enemy.getSweet_potion_count() + enemy.getAgility_boots_count();
                enemyValue += enemyItems * 3.0;

                damageValue += enemyValue;
            }
        }

        logger.info("伤害计算价值:{}",damageValue);
        return damageValue;
    }

    /**
     * 计算阻断价值 - 阻止敌人行动
     */
    private double calculateBlockValue(Position bombPos, GameState gameState) {
        double blockValue = 0;
        int bombRange = calculateBombRange(gameState.getMy_player());

        // 获取爆炸区域
        List<Position> explosionArea = getExplosionArea(bombPos, bombRange, gameState);

        // 检查是否阻断关键路径
        for (PlayerStateVo enemy : getEnemies(gameState)) {
            Position enemyPos = CoordinateConverter.pixelToGrid(enemy.getPosition());

            // 如果炸弹阻断了敌人到重要目标的路径
            if (isBlockingEnemyPath(explosionArea, enemyPos, gameState)) {
                blockValue += 10.0;
            }
        }

        // 如果炸弹控制了战略要点（如地图中心、道具点附近）
        for (Position pos : explosionArea) {
            if (isStrategicPosition(pos, gameState)) {
                blockValue += 5.0;
            }
        }

        return blockValue;
    }

    /**
     * 计算区域控制价值
     */
    private double calculateControlValue(Position bombPos, GameState gameState) {
        double controlValue = 0;
        String myTeam = gameState.getMy_player().getTeam().name();
        int bombRange = calculateBombRange(gameState.getMy_player());

        List<Position> explosionArea = getExplosionArea(bombPos, bombRange, gameState);

        // 计算能影响的敌方占领区域
        for (Position pos : explosionArea) {
            Cell cell = gameState.getCell(pos);
            if (!myTeam.equals(cell.getOwnership().name()) && !"N".equals(cell.getOwnership().name())) {
                controlValue += 3.0; // 威胁敌方占领区
            }
        }

        return controlValue;
    }

    /**
     * 计算破坏价值 - 摧毁可破坏障碍物
     */
    private double calculateDestructionValue(Position bombPos, GameState gameState) {
        double destructionValue = 0;
        int bombRange = calculateBombRange(gameState.getMy_player());

        List<Position> explosionArea = getExplosionArea(bombPos, bombRange, gameState);

        for (Position pos : explosionArea) {
            Cell cell = gameState.getCell(pos);
            if (TerrainEnum.D.equals(cell.getTerrain())) { // 可破坏障碍物
                destructionValue += 10.0; // 每个可破坏物+2分
            }
        }

        logger.info("破坏计算价值:{}",destructionValue);
        return destructionValue;
    }

    /**
     * 获取炸弹爆炸范围
     */
    private List<Position> getExplosionArea(Position bombPos, int range, GameState gameState) {
        List<Position> area = new ArrayList<>();
        area.add(bombPos); // 炸弹中心

        // 四个方向扩展
        addExplosionLine(area, bombPos, range, 1, 0, gameState);   // 右
        addExplosionLine(area, bombPos, range, -1, 0, gameState);  // 左
        addExplosionLine(area, bombPos, range, 0, -1, gameState);   // 下
        addExplosionLine(area, bombPos, range, 0, 1, gameState);  // 上

        return area;
    }

    /**
     * 添加一条爆炸线
     */
    private void addExplosionLine(List<Position> area, Position start, int range, int dx, int dy, GameState gameState) {
        for (int i = 1; i <= range; i++) {
            Position pos = new Position(start.getX() + dx * i, start.getY() + dy * i);

            if (!isValidExplosionPosition(pos, gameState)) {
                break; // 遇到不可破坏障碍物停止
            }

            area.add(pos);
        }
    }

    /**
     * 检查位置是否可以被爆炸影响
     */
    private boolean isValidExplosionPosition(Position pos, GameState gameState) {
        if (!isValidPosition(pos, gameState)) return false;

        Cell cell = gameState.getCell(pos);
        String terrain = cell.getTerrain().name();

        // 不可破坏障碍物阻止爆炸传播
        return !"I".equals(terrain) && !"N".equals(terrain);
    }

    /**
     * 计算炸弹范围（考虑强化药水效果）
     */
    private int calculateBombRange(PlayerStateVo player) {
        int baseRange = 1; // 基础范围
        int potionBonus = player.getSweet_potion_count(); // 强化药水增加范围
        return potionBonus;
    }

    /**
     * 检查是否阻断了敌人路径
     */
    private boolean isBlockingEnemyPath(List<Position> explosionArea, Position enemyPos, GameState gameState) {
        // 简化实现：检查爆炸区域是否在敌人和重要目标之间

        // 检查是否阻断到道具的路径
        for (MapItem item : gameState.getMap_items()) {
            Position itemPos = item.getPosition();
            if (isPathBlocked(enemyPos, itemPos, explosionArea)) {
                return true;
            }
        }

        return false;
    }

    /**
     * 检查路径是否被阻断
     */
    private boolean isPathBlocked(Position start, Position end, List<Position> blockingArea) {
        // 简单的直线路径检查
        int dx = Integer.signum(end.getX() - start.getX());
        int dy = Integer.signum(end.getY() - start.getY());

        Position current = start;
        while (!current.equals(end)) {
            current = new Position(current.getX() + dx, current.getY() + dy);
            if (blockingArea.contains(current)) {
                return true;
            }
        }

        return false;
    }

    // ============ 辅助方法 ============

    private void copyDangerMap(DangerMap source, DangerMap target) {
        // 这里需要DangerMap提供复制方法，暂时用占位实现
        // 实际实现中应该复制所有危险级别数据
    }

    private List<PlayerStateVo> getEnemies(GameState gameState) {
        List<PlayerStateVo> enemies = new ArrayList<>();
        String myTeam = gameState.getMy_player().getTeam().name();

        for (PlayerStateVo player : gameState.getOther_players()) {
            if (!player.getTeam().name().equals(myTeam)) {
                enemies.add(player);
            }
        }

        return enemies;
    }

    private boolean isValidPosition(Position pos, GameState gameState) {
        Cell[][] map = gameState.getMap();
        int x = pos.getY(), y = pos.getX();

        return x >= 0 && x < map.length && y >= 0 && y < map[0].length;
    }

    private boolean isStrategicPosition(Position pos, GameState gameState) {
        Cell cell = gameState.getCell(pos);

        // 加速点是战略位置
        if ("B".equals(cell.getTerrain().name())) return true;

        // 地图中心区域
        Cell[][] map = gameState.getMap();
        int centerX = map.length / 2, centerY = map[0].length / 2;
        int distance = Math.abs(pos.getX() - centerX) + Math.abs(pos.getY() - centerY);

        return distance <= 2;
    }

    /**
     * 获取最佳炸弹放置位置（高级功能）
     */
    public Position getBestBombPosition(GameState gameState, DangerMap dangerMap) {
        Position myPos = CoordinateConverter.pixelToGrid(gameState.getMy_player().getPosition());
        Position bestPos = myPos;
        double bestValue = 0;

        // 搜索当前位置周围的可能位置
        for (int dx = -2; dx <= 2; dx++) {
            for (int dy = -2; dy <= 2; dy++) {
                Position candidate = new Position(myPos.getX() + dx, myPos.getY() + dy);

                if (isValidPosition(candidate, gameState) && hasEscapeRoute(candidate, gameState, dangerMap)) {
                    double value = evaluateBombPlacement(candidate, gameState);
                    if (value > bestValue) {
                        bestValue = value;
                        bestPos = candidate;
                    }
                }
            }
        }

        return bestPos;
    }
}